import json
import time
from concurrent.futures.thread import ThreadPoolExecutor
import uuid
from rest_framework.views import APIView
from wechatpy.work.crypto import WeChatCrypto
from wechatpy.work.exceptions import InvalidCorpIdException
from wechatpy.exceptions import InvalidSignatureException, InvalidAppIdException
from wechatpy.work import parse_message, create_reply

from rest_framework.decorators import action, permission_classes
from rest_framework.permissions import AllowAny
from django.http import HttpResponse
from rest_framework.request import Request
import requests
import threading
from common.util.common import bytes_to_uploaded_file
from dataset.serializers.file_serializers import FileSerializer
from application.serializers.chat_serializers import ChatSerializers
from django.db.models import Q, QuerySet
from application.models import Application
from application.serializers.chat_message_serializers import ChatInfo, ChatMessageSerializer
from django.core.cache import caches
from dataset.serializers.file_serializers import FileSerializer

cache = caches['default_file']
chat_cache = caches['chat_cache']

from xpack.serializers.platform_serializer import ConfigSerializer

thread_pool = ThreadPoolExecutor(max_workers=20)

class WecomMessage(APIView):
    def __init__(self, **kwargs):
        self.chat_id = None
        self.application_id = None
    def chat(self,messages,req):
        # {question} 为用户问题 {trigger_message} 继续
        # chat_record_id_cache_key = req['chat_id'] + '_chat_record_id'
        data = {
            'chat_id': req['chat_id'], 
            'message': messages['message'],
            're_chat': False,
            'stream': False,
            'application_id': req['application_id'],
            'client_id': req['client_id'],
            'form_data': {},
            'image_list': messages['image_list'],
            'document_list': [],
            'audio_list': [],
            'client_type': 'USER',
            'node_id': None,
            'runtime_node_id': None,
            'node_data': {},
            'chat_record_id': None,
            'child_node': {}
        }
        # chat_record_id = None
        chat_record_list = []
        response = ChatMessageSerializer(data = data).chat()
        res_list = []
        if response is None:
            chat_record_list = [{"content": "抱歉，没有查找到相关内容，请重新描述您的问题或提供更多信息。"}]
            chat_cache.set(messages['id'], chat_record_list)
            return messages['id']
        if response.status_code == 200:
            print(json.loads(response.content))
            if response.content is not None:
                chat_record = json.loads(response.content)
                if chat_record['code'] == 200:
                    chat_record_list.append(chat_record['data'])
                    # chat_record_id = chat_record_list[0]['id']
                    # cache.set(chat_record_id_cache_key,chat_record_id)
            elif response.streaming_content is not None:
                res_list = list(response.streaming_content)
                if len(res_list) > 0:
                    for chunk in res_list:
                        if chunk[0:5] == b'data:':
                            jsons = json.loads(chunk[5:].decode('utf-8'))
                            if type(jsons['content']) != str:
                                continue
                            chat_record_list.append(jsons)
                    # chat_record_id = chat_record_list[0]['chat_record_id']
                    # cache.set(chat_record_id_cache_key,chat_record_id)
        # if chat_record_id is not None:
        chat_cache.set(messages['id'], chat_record_list)
        print('生成结果', chat_record_list)
        return chat_record_list
    def get_access_token(self, appid, appsecret):
        access_token_cache_key = appid + '_access_token'
        access_token = cache.get(access_token_cache_key)
        if access_token is None:
            url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={appid}&corpsecret={appsecret}"
            response = requests.get(url)
            data = response.json()
            print(data)
            access_token = data.get('access_token', None)
            if access_token is not None:
                cache.set(access_token_cache_key, access_token, 7200)
        
        return access_token
    def send_custom_message(self, touser, content, wx_config):
        access_token = self.get_access_token(wx_config['app_id'], wx_config['secret'])
        if access_token is None:
            return None
        url = f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}"
        # headers = {'content-type': 'application/json; charset=UTF-8'}
        datas = {
            "touser": touser,
            "msgtype": "text",
            "agentid" : wx_config['agent_id'],
            "text": {
                "content": content
            },
            "safe":0
        }
        data = json.dumps(datas, ensure_ascii=False).encode('utf-8')
        response = requests.post(url, data=data)
        print(response.json())
        return response.json()
    @action(methods=['GET'], detail=False)
    @permission_classes((AllowAny,))
    def get(self, request: Request, application_id: str):
        where = {
            "app_id": application_id,
            "platform": "wecom",
        }
        wx_config = ConfigSerializer.Query(data = where).info()
        if wx_config is None:
            return HttpResponse("微信配置不存在")
        req = {
            "signature": request.GET.get('signature', ''),
            "timestamp": request.GET.get('timestamp', str(time.time())),
            "nonce": request.GET.get('nonce', ''),
            "openid": request.GET.get('openid', ''),
            "echostr": request.GET.get('echostr', ''),
            "encrypt_type": request.GET.get("encrypt_type", "raw"),
            "msg_signature": request.GET.get("msg_signature", ""),
            "application_id": application_id,
            "content": request.body.decode("utf-8"),
            "wechat_access_token": "",
        }
        echo_str = req['echostr']
        crypto = WeChatCrypto(wx_config["token"], wx_config["encoding_aes_key"], wx_config["app_id"])
        try:
            echo_str = crypto.check_signature(
                req['msg_signature'],
                req['timestamp'],
                req['nonce'],
                req['echostr']
            )
        except InvalidSignatureException:
            return HttpResponse('error')
        return HttpResponse(echo_str)
    def post(self, request: Request, application_id: str):
        application = QuerySet(Application).filter(id=application_id).first()
        if application is None:
            return HttpResponse("应用不存在")
        user_id = str(application.user_id)
        where = {
            "app_id": application_id,
            "platform": "wecom",
        }
        wx_config = ConfigSerializer.Query(data = where).info()
        if wx_config is None:
            return HttpResponse("微信配置不存在")
        
        req = {
            "signature": request.GET.get('signature', ''),
            "timestamp": request.GET.get('timestamp', ''),
            "nonce": request.GET.get('nonce', ''),
            "openid": request.GET.get('openid', ''),
            "encrypt_type": request.GET.get("encrypt_type", "raw"),
            "msg_signature": request.GET.get("msg_signature", ""),
            "application_id": application_id,
            "wechat_access_token": "",
            "chat_id": "",
            "user_id": user_id,
        }
        file = open("get.txt", "w")
        file.write(json.dumps(request.GET))
        file.close()
        file = open("body.txt", "w")
        file.write(request.body.decode("utf-8"))
        file.close()
        # POST request
        crypto = WeChatCrypto(wx_config["token"], wx_config["encoding_aes_key"], wx_config["app_id"])
        try:
            msg = crypto.decrypt_message(request.body, req['msg_signature'], req['timestamp'], req['nonce'])
            msg = parse_message(msg)
            req['openid'] = msg.source
            
        except (InvalidSignatureException, InvalidCorpIdException):
            return HttpResponse('消息解密错误')
        
        if req['openid'] == "":
            return HttpResponse("openid为空")
        chat_id_cache_key = application_id + '_chatid_' + req['openid']
        client_id_cache_key = application_id + '_client_' + req['openid']
        client_id = cache.get(client_id_cache_key)
        if client_id is None:
            client_id = str(uuid.uuid1())
            cache.set(client_id_cache_key, client_id)
        chat_id = cache.get(chat_id_cache_key)
        if chat_id is None:
            chat_id = ChatSerializers.OpenChat(data={'user_id':user_id, 'application_id': application_id}).open()
            cache.set(chat_id_cache_key, chat_id)
        req['chat_id'] = chat_id
        req['client_id'] = client_id
        
        # chat_record_id_cache_key = chat_id + '_chat_record_id'
        messages = {
            'id': str(uuid.uuid1()),
            'type': msg.type if msg.type is not None else "text",
            'message': "随便回复点什么",
            'image_list': [],
            'audio_list': [],
        }
        if messages['type'] == 'text':
            messages['message'] = msg.content
        elif messages['type'] == 'image':
            messages['message'] = "请用中文解析图片内容"
            file_name = msg.media_id + '.png'
            file_bytes = requests.get(msg.image).content
            file = bytes_to_uploaded_file(file_bytes, file_name)
            meta = {
                'debug': False,
                'chat_id': chat_id,
                'application_id': application_id,
            }
            file_url = FileSerializer(data={'file': file, 'meta': meta}).upload()
            messages['image_list'] = [{'file_id': file_url.split('/')[-1], 'url': file_url}]
        elif messages['type'] == 'voice':
            messages['message'] = "请用中文解析语音内容"
            if msg.recognition is not None and msg.recognition != "":
                messages['message'] = msg.recognition
            file = self.get_media_info(msg,wx_config)
            meta = {
                'debug': False,
                'chat_id': chat_id,
                'application_id': application_id,
            }
            file_url = FileSerializer(data={'file': file, 'meta': meta}).upload()
            messages['audio_list'] = [{'file_id': file_url.split('/')[-1], 'url': file_url}]
        threading.Thread(target=self.chat, args=(messages, req)).start()
        threading.Thread(target=self.async_reply, args=(messages,req, wx_config)).start()

        return HttpResponse(self.handle_reply(msg,req,wx_config), content_type="application/xml")
        # return HttpResponse("success")
    def handle_reply(self,msg,req,wx_config):
        rcontent = "请稍候，正在处理中。。。"
        if msg.type == 'text':
            reply = create_reply(rcontent, msg)
        elif msg.type == 'image':
            reply = create_reply(rcontent, msg)
        elif msg.type == 'voice':
            reply = create_reply(rcontent, msg)
        else:
            reply = create_reply(rcontent, msg)
        reply_content = reply.render()
        crypto = WeChatCrypto(wx_config["token"], wx_config["encoding_aes_key"], wx_config["app_id"])
        reply_content = crypto.encrypt_message(reply.render(), req['nonce'], req['timestamp'])
        return reply_content
    def async_reply(self, messages, req, wx_config):
        i = 0
        while True:
            time.sleep(3)
            print("聊天记录ID", messages['id'])
            chat_record_list = chat_cache.get(messages['id'])
            print("本次消息", chat_record_list)
            if i >= 10:
                print("抱歉，没有查找到相关内容，请重新描述您的问题或提供更多信息。")
                return False
            i+=1
            if chat_record_list is not None and len(chat_record_list) > 0:
                content = ""
                for chat_record in chat_record_list:
                    content += chat_record['content']
                n = 600
                segments = [content[i:i + n] for i in range(0, len(content), n)]
                for segment in segments:
                    print(segment)
                    self.send_custom_message(req['openid'], segment, wx_config)
                
                return True
  